package com.pandora.credit.service.impl;

import com.pandora.common.util.*;
import com.pandora.credit.dao.CreditDao;
import com.pandora.credit.dto.request.CreditCardRequest;
import com.pandora.credit.dto.request.CreditRequest;
import com.pandora.credit.dto.request.CustomerLoansRequest;
import com.pandora.credit.dto.request.LoanRequest;
import com.pandora.credit.dto.response.*;
import com.pandora.credit.entity.Account;
import com.pandora.credit.entity.Credit;
import com.pandora.credit.exception.AnnouncementNotFoundException;
import com.pandora.credit.exception.auth.AuthorizationTokenInvalidException;
import com.pandora.credit.exception.customer.CustomerNotFoundException;
import com.pandora.credit.mongo.entity.H5Report;
import com.pandora.credit.mongo.entity.MongoCredit;
import com.pandora.credit.mongo.entity.MongoPandoraCredit;
import com.pandora.credit.mongo.service.H5ReportService;
import com.pandora.credit.mongo.service.MongoCreditService;
import com.pandora.credit.mongo.service.MongoPandoraCreditService;
import com.pandora.credit.service.AccountService;
import com.pandora.credit.service.CommonService;
import com.pandora.credit.service.CreditService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.pandora.common.util.Constants.*;

/**
 * @author developer
 */
@Service
public class CreditServiceImpl implements CreditService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private CreditDao creditDao;
    @Autowired
    private CommonService commonService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private MongoPandoraCreditService mongoPandoraCreditService;
    @Autowired
    private MongoCreditService mongoCreditService;
    @Autowired
    private H5ReportService h5ReportService;

    @Override
    public List<Credit> getByCondition(Credit credit) {
        return creditDao.getByCondition(credit);
    }

    @Override
    public void update(Credit credit) {
        creditDao.update(credit);
    }

    @Override
    public LoanResponseNextLong doGetLoansType(String userAgent) {
        Map<String, String> platVerMap = UserAgentUtil.getVersionByUserAgent(userAgent);
        Map<String, Object> reMap = commonService.getCreditFromMongoDb(Constants.CREDIT_TYPES_LOANS_TYPE, 50, -1,
                -1, -1, -1, platVerMap.get("_p"),
                platVerMap.get("_v"), -1, -1);
        Long l = reMap.get("next_id") == null ? null : Long.parseLong(String.valueOf(reMap.get("next_id")));
        return new LoanResponseNextLong(Constants.RETURN_TYPE_LOAN_TYPE, reMap.get("resp_items"), l);
    }

    @Override
    public LoanResponseNextInt doGetLoans(LoanRequest req, String userAgent) {
        long loansTypeId = req.getTypeId();
        int length = req.getLength();
        int nextId = req.getNextId() != null ? req.getNextId() : -1;
        int reCom = req.getRecommend();

        int frontNumber = -1;
        MongoPandoraCredit frontNumberItem = mongoPandoraCreditService.queryByType(Constants.CREDIT_TYPES_LOANS_CONTENT);
        if (frontNumberItem != null
                && frontNumberItem.getItem() != null
                && frontNumberItem.getItem().getNumber() > 0) {
            frontNumber = frontNumberItem.getItem().getNumber();
        }
        if (reCom >= 1) {
            length = -1;
        }
        Map<String, String> platVerMap = UserAgentUtil.getVersionByUserAgent(userAgent);
        Map<String, Object> reMap = commonService.getCreditFromMongoDb(CREDIT_TYPES_LOANS, length, nextId, -1,
                -1, reCom, platVerMap.get("_v"), platVerMap.get("_p"), loansTypeId, frontNumber);

        return new LoanResponseNextInt(Constants.RETURN_TYPE_LOAN,
                reMap.get("resp_items"),
                reMap.get("next_id") == null ? null : Integer.parseInt(String.valueOf(reMap.get("next_id"))));
    }

    @Override
    public LoanResponseNextLong doGetCredits(LoanRequest req, String authorizationToken, String accessToken) {
        int length = req.getLength();
        int nextId = req.getNextId() != null ? req.getNextId() : -1;
        Map<String, Object> map = commonService.getCreditFromMongoDb(Constants.CREDIT_TYPES_CREDITS,
                length, nextId, -1, -1, -1, "", "", -1, -1);
        String appId = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.ACCESS_TOKEN_KEY, accessToken));
        List<Account> accounts = accountService.getByStatus(1);
        String loginName = "";
        if (accounts == null) {
            accounts = new LinkedList<>();
        }
        for (Account account : accounts) {
            if (String.valueOf(account.getId()).equals(appId)) {
                loginName = account.getLoginName();
            }
        }

        Long nextIdLong = map.get("next_id") == null ? null : Long.parseLong(String.valueOf(map.get("next_id")));
        List<MongoPandoraCredit.MongoPandoraCreditItem> items = (List<MongoPandoraCredit.MongoPandoraCreditItem>) map.get("resp_items");
        for (MongoPandoraCredit.MongoPandoraCreditItem k : items) {
            if (!VerifyUtil.isEmpty(authorizationToken) && !VerifyUtil.isEmpty(loginName)) {
                k.setDestUrl(StringUtils.getStrParam(k.getDestUrl(), loginName));
            } else {
                k.setDestUrl("");
            }
        }
        return new LoanResponseNextLong(Constants.RETURN_TYPE_CREDIT,
                items,
                nextIdLong);
    }

    @Override
    public LoanResponseNextNo doGetCustomerCredit(String cusId, String authorizationToken) {
        String mobile = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.AUTHORIZATION_TOKEN_KEY, authorizationToken));
        if (VerifyUtil.isEmpty(mobile)) {
            throw new AuthorizationTokenInvalidException();
        }
        long cusIdTmp = commonService.getCustomerIdByMobile(mobile);
        if (cusIdTmp < 0) {
            throw new CustomerNotFoundException();
        }
        if (!String.valueOf(cusIdTmp).contains(cusId)) {
            throw new CustomerNotFoundException();
        }
        List<Map<String, Object>> reItems = new LinkedList<Map<String, Object>>();
        List<MongoCredit> mongoCredits = mongoCreditService.queryAll();
        for (MongoCredit mc : mongoCredits) {
            Map<String, Object> item = new LinkedHashMap<String, Object>();
            String type = mc.getType();
            if (VerifyUtil.isEmpty(type)) {
                continue;
            }
            type = type.toUpperCase();
            item.put("name", mc.getName());
            item.put("type", type);
            logger.info("cusId[{}] type[{}]", cusId, type);
            List<H5Report> h5Reports = h5ReportService.queryByCusType(Long.parseLong(cusId), type);
            int count = 0;
            if(h5Reports != null){
                count = h5Reports.size();
            }
            item.put("count", count);
            if (count > 0) {
                reItems.add(item);
            }
        }
        return new LoanResponseNextNo(Constants.RETURN_TYPE_CREDIT, reItems);
    }

    @Override
    public LoanResponseNextLong doGetBanks(CreditCardRequest req) {
        int isHot = req.getIsHot();
        int length = req.getLength();
        int nextId = req.getNextId() != null ? req.getNextId() : -1;
        Map<String, Object> map = commonService.getCreditFromMongoDb(Constants.CREDIT_TYPES_BANKS,
                length, nextId, isHot, -1, -1, "", "", -1, -1);

        Long s = map.get("next_id") == null ? null : Long.parseLong(String.valueOf(map.get("next_id")));
        return new LoanResponseNextLong(Constants.RETURN_TYPE_BANK,
                map.get("resp_items"),
                s);
    }

    @Override
    public LoanResponseNextInt doGetCreditCards(CreditCardRequest req) {
        long bankId = req.getBankId();
        int isHot = req.getIsHot();
        int length = req.getLength();
        int nextId = req.getNextId() != null ? req.getNextId() : -1;
        int recommend = req.getRecommend();
        Map<String, Object> map = commonService.getCreditFromMongoDb(Constants.CREDIT_TYPES_CREDIT_CARDS,
                length, nextId, isHot, bankId, recommend, "", "", -1, -1);

        return new LoanResponseNextInt(Constants.RETURN_TYPE_CREDIT_CARD,
                map.get("resp_items"),
                map.get("next_id") == null ? null : Integer.parseInt(String.valueOf(map.get("next_id"))));
    }

    @Override
    public LoanResponseNextStr doCustomerCreditCards(String authorizationToken, CustomerLoansRequest req) {
        int pageLength = req.getLength();
        String nextIdStr = req.getNextId();
        String mobile = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.AUTHORIZATION_TOKEN_KEY, authorizationToken));
        if (VerifyUtil.isEmpty(mobile)) {
            throw new AuthorizationTokenInvalidException();
        }
        long cusId = commonService.getCustomerIdByMobile(mobile);
        if (cusId < 0) {
            throw new CustomerNotFoundException();
        }
        if (pageLength == 0) {
            pageLength = Constants.PAGE_LENGTH_DEFAULT;
        }
        String nextId = DateUtil.getFormatDateTime();
        if (!VerifyUtil.isEmpty(nextIdStr) && !"0".equals(nextIdStr)) {
            nextId = nextIdStr;
        }
        logger.info("get history cusId[{}], pageLength[{}], nextId[{}]", cusId, pageLength, nextId);
        Map<String, Object> reMap = commonService.getHistories(Constants.CREDIT_TYPES_CREDIT_CARDS,
                cusId, pageLength, nextId);

        String s = String.valueOf(reMap.get("next_id"));
        return new LoanResponseNextStr(Constants.RETURN_TYPE_CREDIT_CARD,
                reMap.get("res_list"),
                VerifyUtil.isEmpty(s) || "null".equals(s) ? null : s);
    }

    @Override
    public LoanResponseNextLong doGetPandoralist(String type, CreditRequest req) {
        int label = StringUtils.returnLabelFromType(type);
        Map<String, Object> map = commonService.getCreditFromMongoDb(label, req.getLength(),
                req.getNextId() != null ? Integer.parseInt(String.valueOf(req.getNextId())) : -1, req.getIsHot(),
                req.getBankId(), req.getRecommend(), "", "", -1, -1);
        Long l = map.get("next_id") == null ? null : Long.parseLong(String.valueOf(map.get("next_id")));
        return new LoanResponseNextLong(type, map.get("resp_items"), l);
    }

    @Override
    public PandoraActionsResponse doGetPandoraActions() {
        Credit condition = new Credit();
        condition.setIsValid(CREDIT_STATUS_VALID);
        condition.setType(CREDIT_TYPES_LOANS);
        condition.setIsHot(CREDIT_STATUS_IS_HOT);
        List<Credit> credits = creditDao.getByCondition(condition);
        int count = credits.size();
        if (count == 0) {
            throw new AnnouncementNotFoundException();
        }
        List<Long> ids = credits.stream().map(Credit::getId).collect(Collectors.toList());
        Map<Long, MongoPandoraCredit.MongoPandoraCreditItem> creditsMap = mongoPandoraCreditService.queryByIds(ids).stream()
                .filter(c -> c.getItem() != null).collect(Collectors.toMap(MongoPandoraCredit::getId, c -> c.getItem()));
        List<PandoraActionsResponse.PandoraAction> actions = new LinkedList<>();
        for (int i = 0; i < MagicConst.NUM_100; ++i) {
            int index = i;
            if (index >= count) {
                index %= count;
            }
            Long id = ids.get(index);
            MongoPandoraCredit.MongoPandoraCreditItem item = creditsMap.get(id);
            if (item == null) {
                continue;
            }
            String loanName = item.getLoanName();
            int min = item.getAmount().getMinimum();
            int max = item.getAmount().getMaximum();
            int money;
            Random random = new Random();
            if (min == max || max - min < 100) {
                money = max;
            } else {
                int scope = (max - min) / 100;

                money = min + random.nextInt(scope + 1) * 100;
            }

            String province = PROVINCIES[random.nextInt(PROVINCIES.length)];
            String lastName = LAST_NAMES[random.nextInt(LAST_NAMES.length)];
            String gender = GENDER[random.nextInt(GENDER.length)];
            String announcement = String.format("%s的%s%s在%s成功贷款%d元", province, lastName, gender, loanName, money);
            PandoraActionsResponse.PandoraAction action = new PandoraActionsResponse.PandoraAction(announcement, new String[]{loanName, Integer.toString(money)}, id);
            actions.add(action);
        }
        return new PandoraActionsResponse(actions);
    }
}
